package com.itx.gatewayx.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.itx.gatewayx.common.constants.SystemConstants;
import com.itx.gatewayx.domain.RouteConfig;
import com.itx.gatewayx.mapper.RouteConfigMapper;
import com.itx.gatewayx.service.IDynamicRouteService;
import com.itx.gatewayx.utils.RedisUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 动态路由服务实现
 *
 * @author itx
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DynamicRouteServiceImpl implements IDynamicRouteService, RouteDefinitionRepository, ApplicationEventPublisherAware {

    private final RouteConfigMapper routeConfigMapper;
    private final RedisUtils redisUtils;
    
    /**
     * 路由内存缓存
     */
    private final Map<String, RouteDefinition> routeDefinitionMap = new ConcurrentHashMap<>();
    
    /**
     * 事件发布器
     */
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public void initRoutes() {
        log.info("初始化路由配置");
        List<RouteConfig> routes = routeConfigMapper.selectActiveRoutes();
        if (CollUtil.isEmpty(routes)) {
            log.info("没有有效的路由配置");
            return;
        }
        
        // 清空现有路由
        routeDefinitionMap.clear();
        
        // 加载新路由
        for (RouteConfig route : routes) {
            try {
                RouteDefinition definition = convertToRouteDefinition(route);
                routeDefinitionMap.put(definition.getId(), definition);
                
                // 缓存路由到Redis
                String cacheKey = SystemConstants.ROUTE_CONFIG_KEY + route.getRouteId();
                redisUtils.setCacheObject(cacheKey, route, 
                        Long.parseLong(String.valueOf(redisUtils.getCacheObject(cacheKey))), TimeUnit.SECONDS);
            } catch (Exception e) {
                log.error("路由[{}]加载失败: {}", route.getRouteId(), e.getMessage(), e);
            }
        }
        
        // 发布路由刷新事件
        publisher.publishEvent(new RefreshRoutesEvent(this));
        log.info("路由配置初始化完成，共加载路由{}条", routeDefinitionMap.size());
    }

    @Override
    public boolean refreshRoutes() {
        try {
            // 重新加载路由
            initRoutes();
            return true;
        } catch (Exception e) {
            log.error("刷新路由失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addRoute(RouteConfig routeConfig) {
        if (routeConfig == null || StrUtil.isBlank(routeConfig.getRouteId())) {
            return false;
        }
        
        try {
            // 保存到数据库
            routeConfigMapper.insert(routeConfig);
            
            // 转换为路由定义
            RouteDefinition definition = convertToRouteDefinition(routeConfig);
            routeDefinitionMap.put(definition.getId(), definition);
            
            // 缓存到Redis
            String cacheKey = SystemConstants.ROUTE_CONFIG_KEY + routeConfig.getRouteId();
            redisUtils.setCacheObject(cacheKey, routeConfig);
            
            // 发布刷新路由事件
            publisher.publishEvent(new RefreshRoutesEvent(this));
            return true;
        } catch (Exception e) {
            log.error("添加路由[{}]失败: {}", routeConfig.getRouteId(), e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateRoute(RouteConfig routeConfig) {
        if (routeConfig == null || StrUtil.isBlank(routeConfig.getRouteId())) {
            return false;
        }
        
        try {
            // 保存到数据库
            routeConfigMapper.updateById(routeConfig);
            
            // 转换为路由定义
            RouteDefinition definition = convertToRouteDefinition(routeConfig);
            routeDefinitionMap.put(definition.getId(), definition);
            
            // 更新Redis缓存
            String cacheKey = SystemConstants.ROUTE_CONFIG_KEY + routeConfig.getRouteId();
            redisUtils.setCacheObject(cacheKey, routeConfig);
            
            // 发布刷新路由事件
            publisher.publishEvent(new RefreshRoutesEvent(this));
            return true;
        } catch (Exception e) {
            log.error("更新路由[{}]失败: {}", routeConfig.getRouteId(), e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteRoute(String routeId) {
        if (StrUtil.isBlank(routeId)) {
            return false;
        }
        
        try {
            // 从数据库中删除
            routeConfigMapper.deleteById(routeId);
            
            // 从内存中删除
            routeDefinitionMap.remove(routeId);
            
            // 从Redis中删除
            redisUtils.deleteObject(SystemConstants.ROUTE_CONFIG_KEY + routeId);
            
            // 发布刷新路由事件
            publisher.publishEvent(new RefreshRoutesEvent(this));
            return true;
        } catch (Exception e) {
            log.error("删除路由[{}]失败: {}", routeId, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public RouteDefinition getRoute(String routeId) {
        return routeDefinitionMap.get(routeId);
    }

    @Override
    public List<RouteDefinition> getRoutes() {
        return new ArrayList<>(routeDefinitionMap.values());
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(getRoutes());
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(r -> {
            routeDefinitionMap.put(r.getId(), r);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            routeDefinitionMap.remove(id);
            return Mono.empty();
        });
    }

    @Override
    public RouteDefinition convertToRouteDefinition(RouteConfig routeConfig) {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(routeConfig.getRouteId());
        definition.setUri(URI.create(routeConfig.getUri()));
        definition.setOrder(routeConfig.getRouteOrder());
        
        // 设置断言
        List<PredicateDefinition> predicates = new ArrayList<>();
        if (StrUtil.isNotBlank(routeConfig.getPredicates())) {
            List<Map<String, Object>> predicateList = JSON.parseObject(routeConfig.getPredicates(), new TypeReference<List<Map<String, Object>>>() {});
            for (Map<String, Object> predicateMap : predicateList) {
                PredicateDefinition predicate = new PredicateDefinition();
                String name = predicateMap.get("name").toString();
                predicate.setName(name);
                
                // 获取参数
                if (predicateMap.containsKey("args")) {
                    Map<String, String> args = (Map<String, String>) predicateMap.get("args");
                    predicate.setArgs(args);
                }
                predicates.add(predicate);
            }
        }
        definition.setPredicates(predicates);
        
        // 设置过滤器
        List<FilterDefinition> filters = new ArrayList<>();
        if (StrUtil.isNotBlank(routeConfig.getFilters())) {
            List<Map<String, Object>> filterList = JSON.parseObject(routeConfig.getFilters(), new TypeReference<List<Map<String, Object>>>() {});
            for (Map<String, Object> filterMap : filterList) {
                FilterDefinition filter = new FilterDefinition();
                String name = filterMap.get("name").toString();
                filter.setName(name);
                
                // 获取参数
                if (filterMap.containsKey("args")) {
                    Map<String, String> args = (Map<String, String>) filterMap.get("args");
                    filter.setArgs(args);
                }
                filters.add(filter);
            }
        }
        definition.setFilters(filters);
        
        // 设置元数据
        if (StrUtil.isNotBlank(routeConfig.getMetadata())) {
            Map<String, Object> metadata = JSON.parseObject(routeConfig.getMetadata(), Map.class);
            definition.setMetadata(metadata);
        }
        
        return definition;
    }
} 